The number of application programs written in Java is growing rapidly in number. One of the key reasons for this is the portability of Java code. A brief overview of Java is given below. For more detailed background information on the Java Virtual Machine and the Java language, see Lindholm and Yellin, "The Java Virtual Machine Specification," published by Addison-Wesley. Note that specifications for the Java language and the Java Virtual Machine have been released by Sun Microsystems, Inc.
The Java language is an object-oriented programming language which is compiled to run on a Java Virtual Machine ("Java VM"). A Java VM is a computer which runs on top of the existing hardware and operating system of another computer system. Because the specifications for the Java VM have been published, it is possible to write a Java VM to work with any hardware and/or operating system. Java programs are compiled into bytecode, which will run on any Java VM. The Java VM essentially acts as an interpreter between the Java bytecodes and the system on which the Java program is executing.
There are four major components to a Java VM, all of which are implemented in software. The four components are the registers, the operand stack, the garbage collected heap, and the method area. The method area contains the method code (i.e. the compiled Java code) and symbol tables. The compiled Java code, i.e. the bytecode, consists of a set of instructions. Each instruction consists of a one byte opcode followed by any needed operands.
Compiled Java programs are typically referred to as Java class files. Many Java class files are downloaded from the Internet for execution on a user's computer system. One of the first steps performed by a Java VM is called verification. A class-file verifier (part of the Java VM) ensures that the file truly is a Java class file and will execute without violating any Java security restrictions.
The class file verifier first checks to determine if the class file being loaded is of the correct class file format. This is done by examining the first four bytes of the class file. All Java class files must begin with the "magic number" (i.e. 0xCAFEBABE). A version number follows the magic number, and the class file verifier checks to ensure that the class file being loaded is compatible with the VM loading it. The verifier also checks the information in the constant pool and other sections of the class file for consistency.
During the linking phase, the verifier ensures that all classes except for the Object class have a superclass and that all field and method references in the constant pool have valid names, classes, and type descriptors. In addition, the verifier checks the code array of the code attribute for each method to ensure that all local variables contain values of the appropriate type, that methods are called with the appropriate arguments, and that fields are assigned correct values. The verifier also checks the operand stack for correctness.
Finally, during execution, the verifier checks to ensure that a referenced type is allowed for instructions referencing a type. If an instruction modifies a field or calls a method, the verifier checks to ensure that the field or method is available and that the calling method is allowed to access the field or call the method.
Often, developers would like to measure the performance of a particular Java application in order to identify the sources of delay in the application. Typically, however, the developer only has access to the Java class file and not to the source code. This makes it difficult to insert instrumentation code for measuring and analyzing performance. The Java runtime environment currently provides limited support for performance measurement and analysis. In addition, the class file verifier will not typically allow a class file to execute if it does not comply with all requirements noted above. This means that instrumentation code cannot simply be added into the class file, as this would most likely cause the class file verifier to reject the class file. Similar problems occur whenever a developer desires to add, delete, or modify any code in an existing class file. For example, a developer may desire to add code for the purpose of performing benchmark tests or debugging. A developer may also desire to add, delete, or modify code for the purpose of making functional modifications to the class file.
Consequently, it would be desirable to have a system and method for modifying class files by adding, deleting, or modifying code within the class files. It would be desirable to have a system and method which would follow all class file constraints and thus would not cause class files to be rejected by a class file verifier.